﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using ConsoleAppFramework.Util;

namespace ConsoleAppFramework.Job.TaskFramework
{
    public class MultiThreadWork
    {
        public int ThreadCount { get; private set; }
        private Semaphore sema;

        private int threadNums = 0;
        public MultiThreadWork(int threadCount)
        {
            this.ThreadCount = threadCount;
            sema = new Semaphore(ThreadCount, ThreadCount);

        }
        public void DoMultiWork<T>(SpecificWork<T> work, T arg)
        {
            while (threadNums > ThreadCount)
            {
                Thread.Sleep(100);
            }

            sema.WaitOne();
            ThreadPool.QueueUserWorkItem(p =>
            {
                try
                {
                    Interlocked.Increment(ref threadNums);
                    work((T)p);

                }
                catch (Exception e)
                {
                    ConsoleHelper.WriteErrorLine(e.ToString());
                }
                sema.Release();
                Interlocked.Decrement(ref threadNums);
            }, arg);
        }
        public void DoMultiWork(SpecificWorkVoid work)
        {
            while (threadNums > ThreadCount)
            {
                Thread.Sleep(100);
            }

            sema.WaitOne();
            ThreadPool.QueueUserWorkItem(p =>
            {
                try
                {
                    Interlocked.Increment(ref threadNums);
                    work();

                }
                catch (Exception e)
                {
                    ConsoleHelper.WriteErrorLine(e.ToString());
                }
                sema.Release();
                Interlocked.Decrement(ref threadNums);
            });
        }

        /// <summary>
        /// 执行循环while true任务
        /// </summary>
        /// <param name="action">while true里的action</param>
        /// <param name="threadCount">运行线程数</param>
        /// <param name="waitSeconds">等待时间</param>
        public static void RunLoopTasks(Action action, int threadCount = 1, int waitSeconds = 0)
        {
            for (int i = 0; i < threadCount; i++)
            {
                System.Threading.Tasks.Task.Run(action: () => {
                    while (true)
                    {
                        try
                        {
                            action();
                        }
                        catch (Exception ex)
                        {
                            ConsoleHelper.WriteErrorLine(ex.Message);
                        }

                        if (waitSeconds > 0)
                        {
                            Thread.Sleep(waitSeconds * 1000);
                        }
                    }
                });
            }
        }

        public static void MultiThreadExec(Action action, int threadCount = 1, Action finish = null)
        {
            var threadList = new List<Thread>();
            for (int i = 0; i < threadCount; i++)
            {
                var t = new Thread(() => { action?.Invoke(); });
                threadList.Add(t);
                t.Start();
            }
            while (true)
            {
                //线程是否还是进行 如果在action中使用了Thread.Sleep 会导致线程休眠状态为ThreadState.WaitSleepJoin
                // || x.ThreadState == ThreadState.WaitSleepJoin
                var isProceed = threadList.Any(x => x.ThreadState == ThreadState.Running);
                if (!isProceed) break;
                Thread.Sleep(3 * 1000);
            }
            finish?.Invoke();
        }

        public void WaitingFinish()
        {
            for (int i = 0; i < ThreadCount; i++)
            {
                sema.WaitOne();
            }
            sema.Release(ThreadCount);
        }
        public delegate void SpecificWork<in T>(T one);
        public delegate void SpecificWorkVoid();
    }
}
